home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / que1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  10.1 KB  |  589 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: que1.c,v 2.4 84/10/26 12:04:28 guido Exp $";
  3.  
  4. /*
  5.  * B editor -- Manipulate queues of nodes, lower levels.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "feat.h"
  10. #include "bobj.h"
  11. #include "node.h"
  12. #include "supr.h"
  13. #include "queu.h"
  14. #include "gram.h"
  15.  
  16. #include <ctype.h>
  17.  
  18.  
  19. value grab_com();
  20.  
  21.  
  22. /*
  23.  * Append queue 2 to the end of queue 1.
  24.  */
  25.  
  26. Visible Procedure
  27. joinqueues(pq, q)
  28.     register queue *pq;
  29.     register queue q;
  30. {
  31.     if (emptyqueue(q))
  32.         return;
  33.     while (*pq) {
  34.         if (Refcnt(*pq) > 1)
  35.             uniql((value*)pq);
  36.         pq = &(*pq)->q_link;
  37.     }
  38.     *pq = q;
  39. }
  40.  
  41.  
  42. /*
  43.  * Prepend a node to a queue ("push").
  44.  * Empty strings and Optional holes are silently discarded.
  45.  */
  46.  
  47. Visible Procedure
  48. preptoqueue(n, pq)
  49.     node n;
  50.     register queue *pq;
  51. {
  52.     register queue q;
  53.  
  54.     if (Type(n) == Tex) {
  55.         int len = Length((value)n);
  56.         if (len == 0)
  57.             return;
  58.         n = nodecopy(n);
  59.     }
  60.     else { /* Avoid Optional holes */
  61.         if (symbol(n) == Optional)
  62.             return;
  63.         n = nodecopy(n);
  64.     }
  65.     q = (queue) grab_com(2);
  66.     q->q_data = n;
  67.     q->q_link = *pq;
  68.     *pq = q;
  69. }
  70.  
  71.  
  72. /*
  73.  * Append a node to the end of a queue (same extras as preptoqueue).
  74.  */
  75.  
  76. Visible Procedure
  77. addtoqueue(pq, n)
  78.     register queue *pq;
  79.     register node n;
  80. {
  81.     auto queue q = Qnil;
  82.  
  83.     preptoqueue(n, &q);
  84.     joinqueues(pq, q);
  85. }
  86.  
  87.  
  88. /*
  89.  * Push a string onto a queue.
  90.  */
  91.  
  92. Visible Procedure
  93. stringtoqueue(str, pq)
  94.     register string str;
  95.     register queue *pq;
  96. {
  97.     register value  v;
  98.  
  99.     if (str == NULL)
  100.         return;
  101.     v = mk_text(str);
  102.     preptoqueue((node) v, pq);
  103.     release(v);
  104. }
  105.  
  106.  
  107. /*
  108.  * Append a string to a queue.
  109.  */
  110.  
  111. Visible Procedure
  112. addstringtoqueue(pq, str)
  113.     register queue *pq;
  114.     register string str;
  115. {
  116.     register value v = mk_text(str);
  117.  
  118.     addtoqueue(pq, (node) v);
  119.     release(v);
  120. }
  121.  
  122.  
  123. /*
  124.  * Get the first node of a queue and delink it ("pop").
  125.  */
  126.  
  127. Visible node
  128. queuebehead(pq)
  129.     register queue *pq;
  130. {
  131.     register node n;
  132.     register queue q = *pq;
  133.  
  134.     Assert(q);
  135.  
  136.     n = nodecopy(q->q_data);
  137.     *pq = qcopy(q->q_link);
  138.     qrelease(q);
  139.     return n;
  140. }
  141.  
  142.  
  143. /*
  144.  * Split a node in successive queue elements which are pushed
  145.  * on the queue using preptoqueue.
  146.  * 'Atomic' nodes (texts and holes) are pushed unadorned.
  147.  */
  148.  
  149. Visible Procedure
  150. splitnode(n, pq)
  151.     register node n;
  152.     register queue *pq;
  153. {
  154.     register node nn;
  155.     register string *rp;
  156.     register int i;
  157.     register int sym;
  158.  
  159.     if (Type(n) == Tex) {
  160.         preptoqueue(n, pq);
  161.         return;
  162.     }
  163.     sym = symbol(n);
  164.     if (sym == Optional)
  165.         return;
  166.     if (sym == Hole) {
  167.         preptoqueue(n, pq);
  168.         return;
  169.     }
  170.  
  171.     rp = noderepr(n);
  172.     for (i = nchildren(n); i >= 0; --i) {
  173.         if (rp[i] && rp[i][0])
  174.             stringtoqueue(rp[i], pq);
  175.         if (i) {
  176.             nn = child(n, i);
  177.             if (Type(nn) == Tex || symbol(nn) != Optional)
  178.                 preptoqueue(nn, pq);
  179.         }
  180.     }
  181. }
  182.  
  183.  
  184. /*
  185.  * Substitute the focus for its parent, appending the remainder of
  186.  * the parent to the queue.
  187.  * The focus must be the first child and not preceded by fixed text.
  188.  * The focus must be allowed in the place of its parent.
  189.  * If any of these conditions is not met, No is returned and nothing
  190.  * is changed.
  191.  */
  192.  
  193. Visible bool
  194. resttoqueue(pp, pq)
  195.     register path *pp;
  196.     register queue *pq;
  197. {
  198.     auto queue q = Qnil;
  199.     register path pa = parent(*pp);
  200.     register node n = tree(*pp);
  201.     register int sym = symbol(n);
  202.     /* register markbits x; */
  203.  
  204.     if (!pa || ichild(*pp) != 1
  205.         || fwidth(noderepr(tree(pa))[0]) != 0 || !allowed(pa, sym))
  206.         return No;
  207.  
  208.     n = nodecopy(n);
  209.     /* x = marks(n); */
  210.     up(pp) || Abort();
  211.     splitnode(tree(*pp), &q);
  212.     noderelease(queuebehead(&q));
  213.     replace(pp, n);
  214.     /* if (x) { */
  215.         /* markpath(pp, x); */ /* Actually, should restore all n's marks? */
  216.     /* } */
  217.     joinqueues(pq, q);
  218.     return Yes;
  219. }
  220.  
  221.  
  222. /*
  223.  * Like resttoqueue, but exactly from current position in fixed text.
  224.  * Also, it cannot fail.
  225.  */
  226.  
  227. Visible Procedure
  228. nosuggtoqueue(ep, pq)
  229.     register environ *ep;
  230.     queue *pq;
  231. {
  232.     auto queue q = Qnil;
  233.     register int i;
  234.     register string *rp;
  235.     register node n;
  236.     register node nn;
  237.     register int sym;
  238.     string str;
  239.  
  240.     if (issuggestion(ep))
  241.         return;
  242.     Assert((ep->mode == FHOLE || ep->mode == VHOLE) && (ep->s1&1));
  243.  
  244.     n = tree(ep->focus);
  245.     rp = noderepr(n);
  246.     for (i = nchildren(n); i > ep->s1/2; --i) {
  247.         if (!Fw_zero(rp[i]))
  248.             stringtoqueue(rp[i], &q);
  249.         nn = child(n, i);
  250.         sym = symbol(nn);
  251.         if (sym != Optional) {
  252.             preptoqueue(nn, &q);
  253.             if (sym != Hole) {
  254.                 s_downi(ep, i);
  255.                 delfocus(&ep->focus);
  256.                 s_up(ep);
  257.             }
  258.         }
  259.     }
  260.     str = rp[i];
  261.     if (str && str[ep->s2]) /* Push partial first text */
  262.         stringtoqueue(str + ep->s2, &q);
  263.     joinqueues(pq, q);
  264. }
  265.  
  266.  
  267. /*
  268.  * Check whether the remainder of the current node is all suggestion.
  269.  */
  270.  
  271. Visible bool
  272. issuggestion(ep)
  273.     register environ *ep;
  274. {
  275.     register node n;
  276.     register int nch;
  277.     register int sym;
  278.     register int i;
  279.  
  280.     if (ep->mode != VHOLE && ep->mode != FHOLE || !(ep->s1&1))
  281.         return No; /* Actually wrong call? */
  282.  
  283.     n = tree(ep->focus);
  284.     nch = nchildren(n);
  285.     for (i = ep->s1/2 + 1; i <= nch; ++i) {
  286.         sym = symbol(child(n, i));
  287.         if (sym != Hole && sym != Optional)
  288.             return No;
  289.     }
  290.     return Yes;
  291. }
  292.  
  293.  
  294. /*
  295.  * See if a node fits in a hole.
  296.  */
  297.  
  298. Visible bool
  299. fitnode(pp, n)
  300.     register path *pp;
  301.     register node n;
  302. {
  303.     if (!allowed(*pp, symbol(n)))
  304.         return No;
  305.     replace(pp, nodecopy(n));
  306.     return Yes;
  307. }
  308.  
  309.  
  310. /*
  311.  * Fit a string in a hole.
  312.  * Returns the number of characters consumed.
  313.  * (This does not have to be the maximum possible, but a reasonable attempt
  314.  * is made.  If the internal buffer is exhausted, it leaves the rest for
  315.  * another call.)
  316.  */
  317.  
  318. Visible int
  319. fitstring(pp, str, alt_c)
  320.     register path *pp;
  321.     register string str;
  322.     int alt_c;
  323. {
  324.     environ dummyenv;
  325.     register node n;
  326.     register int ich;
  327.     register int len;
  328.     register string cp;
  329.     char buf[1024];
  330.  
  331.     Assert(str);
  332.     if (!str[0])
  333.         return 0;
  334.     if (!insguess(pp, str[0], &dummyenv)) {
  335.         if (!alt_c)
  336.             return 0;
  337.         if (!insguess(pp, alt_c, &dummyenv))
  338.             return 0;
  339.     }
  340.     if (Type(tree(*pp)) == Tex)
  341.         up(pp) || Abort();
  342.     if (dummyenv.mode == FHOLE) {
  343.         cp = noderepr(tree(*pp))[0];
  344.         len = 1;
  345.         if (cp) {
  346.             ++str;
  347.             ++cp;
  348.             while (*str >= ' ' && *str == *cp) {
  349.                 ++len;
  350.                 ++str;
  351.                 ++cp;
  352.             }
  353.         }
  354.         return len;
  355.     }
  356.     if (dummyenv.mode == VHOLE) {
  357.         buf[0] = str[0];
  358.         ++str;
  359.         len = 1;
  360.         n = tree(*pp);
  361.         ich = dummyenv.s1/2;
  362.         while (*str && mayinsert(n, ich, len, *str) && len < sizeof buf - 1) {
  363.             buf[len] = *str;
  364.             ++str;
  365.             ++len;
  366.         }
  367.         if (len > 1) {
  368.             buf[len] = 0;
  369.             downi(pp, ich) || Abort();
  370.             replace(pp, (node) mk_text(buf));
  371.             up(pp) || Abort();
  372.         }
  373.         return len;
  374.     }
  375.     return 1;
  376. }
  377.  
  378.  
  379. /*
  380.  * Set the focus position (some VHOLE/FHOLE setting, probably)
  381.  * at the 'len'th character from the beginning of the current node.
  382.  * This may involve going to a child or moving beyond the current subtree.
  383.  * Negative 'len' values may be given to indicate negative widths;
  384.  * this is implemented incomplete.
  385.  */
  386.  
  387. Visible Procedure
  388. fixfocus(ep, len)
  389.     register environ *ep;
  390.     register int len;
  391. {
  392.     node nn;
  393.     register node n = tree(ep->focus);
  394.     register string *rp;
  395.     register int i = 0;
  396.     register int nch;
  397.     register int w;
  398.  
  399.     if (Type(n) == Tex) {
  400.         w = Length((value)n);
  401.         Assert(w >= len && len >= 0);
  402.         if (w > len)
  403.             ep->spflag = No;
  404.         ep->mode = VHOLE;
  405.         ep->s1 = ichild(ep->focus) * 2;
  406.         ep->s2 = len;
  407.         s_up(ep);
  408.         return;
  409.     }
  410.     nch = nchildren(n);
  411.     w = width(n);
  412.     if (len > w && w >= 0) {
  413.         i = ichild(ep->focus); /* Change initial condition for for-loop */
  414.         if (!up(&ep->focus)) {
  415.             ep->mode = ATEND;
  416.             return;
  417.         }
  418.         higher(ep);
  419.         n = tree(ep->focus);
  420.     }
  421.  
  422.     rp = noderepr(n);
  423.     for (; i <= nch; ++i) {
  424.         if (i) {
  425.             nn = child(n, i);
  426.             w = width(nn);
  427.             if (w < 0 || w >= len && len >= 0) {
  428.                 s_downi(ep, i);
  429.                 fixfocus(ep, len);
  430.                 return;
  431.             }
  432.             if (len >= 0)
  433.                 len -= w;
  434.         }
  435.         w = Fwidth(rp[i]);
  436.         if (w >= len && len >= 0) {
  437.             if (w > len)
  438.                 ep->spflag = No;
  439.             ep->mode = FHOLE;
  440.             ep->s1 = 2*i + 1;
  441.             ep->s2 = len;
  442.             return;
  443.         }
  444.         else if (w < 0)
  445.             len = 0;
  446.         else
  447.             len -= w;
  448.     }
  449.     ep->mode = ATEND;
  450. }
  451.  
  452.  
  453. /*
  454.  * Apply, if possible, a special fix relating to spaces:
  455.  * when a space has been interpreted as joining character
  456.  * and we end up in the following hole, but we don't succeed
  457.  * in filling the hole; it is then tried to delete the hole
  458.  * and the space.
  459.  * Usually this doesn't occur, but it may occur when inserting
  460.  * after a space that was already fixed on the screen but now
  461.  * deserves re-interpretation.
  462.  */
  463.  
  464. Visible bool
  465. spacefix(ep)
  466.     environ *ep;
  467. {
  468.     path pa;
  469.     node n;
  470.     string *rp;
  471.  
  472.     if (ichild(ep->focus) != 2 || symbol(tree(ep->focus)) != Hole)
  473.         return No;
  474.     pa = parent(ep->focus);
  475.     n = tree(pa);
  476.     rp = noderepr(n);
  477.     if (!Fw_zero(rp[0]) || Fwidth(rp[1]) != 1 || rp[1][0] != ' ')
  478.         return No;
  479.     n = firstchild(n);
  480.     if (!allowed(pa, symbol(n)))
  481.         return No;
  482.     s_up(ep);
  483.     replace(&ep->focus, nodecopy(n));
  484.     ep->mode = ATEND;
  485.     ep->spflag = Yes;
  486.     return Yes;
  487. }
  488.  
  489.  
  490. /*
  491.  * Prepend a subset of a node to a queue.
  492.  */
  493.  
  494. Visible Procedure
  495. subsettoqueue(n, s1, s2, pq)
  496.     register node n;
  497.     register int s1;
  498.     register int s2;
  499.     register queue *pq;
  500. {
  501.     register string *rp = noderepr(n);
  502.  
  503.     for (; s2 >= s1; --s2) {
  504.         if (s2&1)
  505.             stringtoqueue(rp[s2/2], pq);
  506.         else
  507.             preptoqueue(child(n, s2/2), pq);
  508.     }
  509. }
  510.  
  511. #ifdef SHOWBUF
  512.  
  513. /*
  514.  * Produce flat text out of a queue's first line, to show it on screen.
  515.  */
  516.  
  517. Visible string
  518. querepr(qv)
  519.     value qv;
  520. {
  521.     queue q = (queue)qv;
  522.     node n;
  523.     static char buf[1000]; /***** Cannot overflow? *****/
  524.     string cp;
  525.     string sp;
  526.     string *rp;
  527.     int nch;
  528.     int i;
  529.     int len;
  530.  
  531.     cp = buf;
  532.     for (; q; q = q->q_link) {
  533.         n = q->q_data;
  534.         if (Type(n) == Tex) {
  535.             for (sp = Str((value) n); cp < buf+80 && *sp; ++sp) {
  536.                 if (!isprint(*sp) && *sp != ' ')
  537.                     break;
  538.                 *cp++ = *sp;
  539.             }
  540.             if (*sp == '\n') {
  541.                 if (!emptyqueue(q->q_link)) {
  542.                     strcpy(cp, " ...");
  543.                     cp += 4;
  544.                 }
  545.                 break;
  546.             }
  547.         }
  548.         else {
  549.             rp = noderepr(n);
  550.             nch = nchildren(n);
  551.             for (i = 0; i <= nch; ++i) {
  552.                 if (i > 0) {
  553.                     if (Type(child(n, i)) == Tex) {
  554.                         len = Length((value)child(n, i));
  555.                         if (len > 80)
  556.                             len = 80;
  557.                         strncpy(cp, Str((value)child(n, i)), len);
  558.                         cp += len;
  559.                     }
  560.                     else {
  561.                         strcpy(cp, "...");
  562.                         cp += 3;
  563.                     }
  564.                 }
  565.                 if (Fw_negative(rp[i])) {
  566.                     strcpy(cp, " ...");
  567.                     cp += 4;
  568.                     break;
  569.                 }
  570.                 if (Fw_positive(rp[i])) {
  571.                     strcpy(cp, rp[i]);
  572.                     while (*cp)
  573.                         ++cp;
  574.                     if (cp[-1] == '\t' || cp[-1] == '\b')
  575.                         --cp;
  576.                 }
  577.             }
  578.         }
  579.         if (cp >= buf+80) {
  580.             strcpy(buf+76, "...");
  581.             break;
  582.         }
  583.     }
  584.     *cp = 0;
  585.     return buf;
  586. }
  587.  
  588. #endif SHOWBUF
  589.